home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Mac Game Programming Gurus / TricksOfTheMacGameProgrammingGurus.iso / CodeWarrior Lite / Metrowerks C⁄C++ Lite / Headers / System Extras Headers / GX Graphics Libraries / font menu library.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-17  |  22.3 KB  |  716 lines  |  [TEXT/MMCC]

  1. /* graphics:    
  2.     gxFont menu library routines
  3.     by Cary Clark, Georgiann Delaney, Michael Fairman, Dave Good, Robert Johnson, Keith McGreggor, Mike Reed, Oliver Steele, David Van Brink, Chris Yerga
  4.     Copyright ©1987 - 1991 Apple Computer, Inc.  All rights reserved.
  5. */
  6.  
  7. #include <Resources.h>
  8. #include <Menus.h>
  9. #include <Memory.h>
  10. #include <ToolUtils.h>
  11. #include <Types.h>
  12. #include <Fonts.h>
  13.  
  14. #include "graphics types.h"
  15. #include "font menu library.h"
  16. #include "font routines.h"
  17. #include "font library.h"
  18. #include "graphics routines.h"
  19. #include "layout routines.h"
  20. #if !defined(__powerc)
  21.     pascal Handle XGetNextFOND(Handle fontHandle) = {0x700A, 0xA822}; /* this disappeared in the latest release of THINK C */
  22. #else
  23.     #define XGetNextFOND GetNextFOND
  24. #endif
  25.  
  26. /*****************************************
  27.  *  Menu manager library routines to handle fonts *
  28.  *****************************************/
  29.  
  30. void DeleteMenuItems(MenuHandle menuH)
  31. {
  32.     int i;
  33.  
  34.     for (i = CountMItems(menuH); i > 0; --i)
  35.         DelMenuItem(menuH, i);
  36. }
  37.  
  38. static long AppendMenuName(MenuHandle menu, long length, unsigned char name[])
  39. {
  40.     name[0] = length < 255 ? length : 255;
  41.     AppendMenu(menu, (const unsigned char *) "\pfont name");  /*** some full names disable the item */ /* cast for Think C 4.0 */
  42.     SetMenuItemText(menu, CountMItems(menu), name);
  43.     return length > 255;
  44. }
  45.  
  46. static MenuHandle NewMenuName(short menuID, long length, unsigned char *title)
  47. {
  48.     Str255 str;
  49.  
  50.     str[0] = length < 255 ? length : 255;
  51.     BlockMove(title+1, &str[1], str[0]);
  52.     return NewMenu(menuID, str);
  53. }
  54.  
  55. static int Str255Compare(Str255 a, Str255 b)
  56. {
  57.     int i, minSize = a[0] < b[0] ? a[0] : b[0];
  58.  
  59.     for (i = 1; i < minSize; i++) {
  60.         if (a[i] == b[i])
  61.             continue;
  62.         return a[i] - b[i];
  63.     }
  64.     return a[0] - b[0];
  65. }
  66.  
  67. /*
  68. *       sorts the text, command char, and item mark 
  69. *       this way any submenus will sort with the  item     
  70.  *  THIS SHOULD CALL SOME COOL INTL. SORT ROUTINE
  71.  */
  72. void SortMenu(MenuHandle menu)
  73. {
  74.     short i, j, count = CountMItems(menu);
  75.     
  76.     for (i = 2; i <= count; i++)
  77.         for (j = count; j >= i; --j) {
  78.             short lowercmdChar, uppercmdChar;
  79.             short lowermarkChar, uppermarkChar;
  80.             Str255 lower, upper;
  81.             GetMenuItemText(menu, j, lower);
  82.             GetMenuItemText(menu, j-1, upper);
  83.             GetItemCmd ( menu, j, &lowercmdChar );
  84.             GetItemCmd ( menu, j-1, &uppercmdChar );
  85.             GetItemMark ( menu, j, &lowermarkChar );
  86.             GetItemMark ( menu, j-1, &uppermarkChar );
  87.             
  88.             if (Str255Compare(lower, upper) < 0) {
  89.                 SetMenuItemText(menu, j, upper);
  90.                 SetMenuItemText(menu, j-1, lower);
  91.                 SetItemCmd ( menu, j, uppercmdChar );
  92.                 SetItemCmd ( menu, j-1, lowercmdChar );
  93.                 SetItemMark ( menu, j, uppermarkChar );
  94.                 SetItemMark ( menu, j-1, lowermarkChar );
  95.             }
  96.         }
  97. }
  98.  
  99. /*
  100.  *  Append a menu with the fonts' full names
  101.  */
  102. long FontMenu(MenuHandle menu)
  103. {
  104.     return FontPlatformMenu(menu, gxNoPlatform, gxNoScript, gxNoLanguage);
  105. }
  106.  
  107. /*
  108.  *  Append a menu with the fonts' full names for fonts that support the specified platform
  109.  */
  110. long FontPlatformMenu(MenuHandle menu, gxFontPlatform platform, gxFontScript script, gxFontLanguage language)
  111. {
  112.     gxFont* fonts;
  113.     long i, count, nameIndex;
  114.     
  115.     count = GXFindFonts(nil, 0, platform, script, language, 0, nil, 1, gxSelectToEnd, 0);
  116.     fonts = (gxFont*)NewPtr(count * sizeof(gxFont));
  117.     GXFindFonts(nil, 0, platform, script, language, 0, nil, 1, count, fonts);
  118.  
  119.     for (i = 0; i < count; i++)
  120.     {   unsigned char *name; 
  121.         long length;
  122.          
  123.         if ((length = GXFindFontName(fonts[i], gxFullFontName, gxMacintoshPlatform, gxRomanScript, gxEnglishLanguage, nil, &nameIndex)) > 0) {
  124.             name = (unsigned char *) NewPtr(length + 1);
  125.             GXGetFontName(fonts[i], nameIndex, nil, nil, nil, nil, &name[1]);
  126.             AppendMenuName(menu, length, name);
  127.             DisposePtr((Ptr) name);
  128.         } 
  129.     }
  130.     DisposePtr((Ptr)fonts);
  131.     SortMenu(menu);
  132.     return count;
  133. }
  134.  
  135. /*
  136.  *  Append a menu with the fonts' family names
  137.  */
  138. long FontFamilyMenu(MenuHandle menu)
  139. {
  140.     return FontFamilyPlatformMenu(menu, gxNoPlatform, gxNoScript, gxNoLanguage);
  141. }
  142.  
  143. long FontFamilyPlatformMenu(MenuHandle menu, gxFontPlatform platform, gxFontScript script, gxFontLanguage language)
  144. {
  145.     gxFont* fonts;
  146.     long i, count;
  147.     
  148.     count = GXFindFonts(nil, gxFamilyFontName, platform, script, language, 0, nil, 1, gxSelectToEnd, nil);
  149.     fonts = (gxFont*)NewPtr(count * sizeof(gxFont));
  150.     GXFindFonts(nil, gxFamilyFontName, platform, script, language, 0, nil, 1, count, fonts);
  151.  
  152.     for (i = 0; i < count; i++)
  153.     {    unsigned char name[256];
  154.         
  155.             name[0] = GXFindFontName(fonts[i], gxFamilyFontName, gxMacintoshPlatform, gxRomanScript, gxEnglishLanguage, &name[1], nil);
  156.         if (name[0])
  157.             AppendMenuName(menu, name[0], name);
  158.     }
  159.     DisposePtr((Ptr)fonts);
  160.     SortMenu(menu);
  161.     return count;
  162. }
  163.  
  164. /*
  165.  *  Create a menu with the given gxFont family's name, filled with the styles available in that family
  166.  */
  167. MenuHandle FontStyleMenu(short menuID, gxFont family)
  168. {
  169.     long i, count = CountFontStyles(family);
  170.     long length;
  171.     MenuHandle menu;
  172.     unsigned char *name;
  173.  
  174.     if ((length = GXFindFontName(family, gxFamilyFontName, gxMacintoshPlatform, gxRomanScript, gxEnglishLanguage, nil, nil)) > 0) {
  175.         name = (unsigned char *) NewPtr(length + 1);
  176.         GXFindFontName(family, gxFamilyFontName, gxMacintoshPlatform, gxRomanScript, gxEnglishLanguage, &name[1], nil);
  177.         menu = NewMenuName(menuID, length, name);
  178.         DisposePtr((Ptr) name);
  179.     } else
  180.         menu = NewMenu(menuID, (unsigned char *) "\pNo family name");    /* cast for Think C 4.0 */
  181.  
  182.     for (i = 1; i <= count; i++) {
  183.         gxFont sfnt = FindFontStyle(family, i, 0, 0, 0, 0, nil);
  184.         if ((length = GXFindFontName(sfnt, gxStyleFontName, gxMacintoshPlatform, gxRomanScript, gxEnglishLanguage, nil, nil)) > 0) {
  185.             name = (unsigned char *) NewPtr(length + 1);
  186.             GXFindFontName(sfnt, gxStyleFontName, gxMacintoshPlatform, gxRomanScript, gxEnglishLanguage, &name[1], nil);
  187.             AppendMenuName(menu, length, name);
  188.             DisposePtr((Ptr)name);
  189.         }
  190.     }
  191.     SortMenu(menu);
  192.  
  193.     return menu;
  194. }
  195.  
  196. /*********************************************/
  197. /*                  HierFontMenu                        */
  198. /*                                                  */
  199. /*          the firstHierMenuID let's the application decide        */
  200. /*          what number the heir menu IDs start                     */ 
  201. /*                                                  */
  202. /*********************************************/
  203. short HierFontMenu(MenuHandle theMenu, short firstHierMenuID, fontFilterProc proc, fontMenuAttribute attr)
  204. {
  205.     long        i, count;
  206.     short    heirsUsed = 0;
  207.     long        howManyInstances;
  208.     long        howManyVariations;
  209.     gxFontVariation        *variations;
  210.     gxFontName        fontNameID;
  211.  
  212.     count = GXFindFonts(nil, 0, 0, 0, 0, 0, nil, 1, gxSelectToEnd, 0);
  213.     for (i = 1; i <= count; i++)
  214.     {    gxFont fontID;
  215.         long length;
  216.  
  217.         GXFindFonts(nil, 0, 0, 0, 0, 0, nil, i, 1, &fontID);
  218.         if (proc && !proc(fontID))
  219.             continue;
  220.         length = GXFindFontName(fontID, gxFamilyFontName, gxMacintoshPlatform, gxRomanScript, gxEnglishLanguage, nil, nil);
  221.         if (length)
  222.         {
  223.             unsigned char *name;
  224.             Boolean alreadyInMenu = false;
  225.             short numMItem;
  226.             short k;
  227.  
  228.             name = (unsigned char *) NewPtr(length + 1);
  229.             GXFindFontName(fontID, gxFamilyFontName, gxMacintoshPlatform, gxRomanScript, gxEnglishLanguage, &name[1], nil);
  230.             numMItem = CountMItems(theMenu);/*how many items have i already added to the menu*/
  231.             for (k=1; k<= numMItem; k++)    /*check to see if the name is already in the menu*/
  232.             {
  233.                 Str255      str;
  234.  
  235.                 GetMenuItemText (theMenu, k, str);
  236.                 name[0] = length; /*fake str255*/
  237.                 if ( !Str255Compare(str, name) ) 
  238.                     alreadyInMenu = true;
  239.             }
  240.             if (!alreadyInMenu)         /*if not then add it*/
  241.             {
  242.                 MenuHandle hMenu;
  243.  
  244.                 AppendMenuName(theMenu, length, name);
  245.                 hMenu = FontStyleMenu(heirsUsed + firstHierMenuID, fontID);
  246.                 howManyInstances = (attr & noInstancesFontMenu) ? 0 : GXCountFontInstances(fontID);
  247.                 if( ( (CountMItems(hMenu)) > 1) || (howManyInstances > 0) )/*only add it if it is more than one item*/
  248.                 {   
  249.                     InsertMenu (hMenu, -1);
  250.                     
  251.                     SetItemCmd(theMenu, numMItem+1, hMenuCmd);
  252.                     SetItemMark(theMenu, numMItem+1, heirsUsed + firstHierMenuID);
  253.                     heirsUsed ++;
  254.                 }
  255.                 
  256.                 if(howManyInstances)
  257.                 {
  258.                     short m;
  259.                     
  260.                     howManyVariations = GXCountFontVariations(fontID);
  261.                     variations = (gxFontVariation*)NewPtr(sizeof(gxFontVariation) * howManyVariations);
  262.                     
  263.                     AppendMenu(hMenu, (const unsigned char *) "\p(-" );    /*dotted gxLine*/
  264.                     for(m = 1; m<=howManyInstances; m++)
  265.                     {
  266.                         DisposePtr((Ptr) name);
  267.                         fontNameID = GXGetFontInstance(fontID, m, variations);
  268.                         if ((length = GXFindFontName(fontID, fontNameID, gxMacintoshPlatform, gxRomanScript, gxEnglishLanguage, nil, nil)) > 0) 
  269.                         {
  270.                             name = (unsigned char *) NewPtr(length+1);
  271.                             GXFindFontName(fontID, fontNameID, gxMacintoshPlatform, gxRomanScript, gxEnglishLanguage, &name[1], nil);
  272.                             AppendMenuName(hMenu, length, name);
  273.                         }
  274.                     }
  275.                 }
  276.             }
  277.             DisposePtr((Ptr) name);
  278.         } 
  279.     }
  280.     SortMenu(theMenu);
  281.     return(heirsUsed);
  282. }
  283.  
  284.  
  285. gxFont DoHierFontMenuCommand(long menuResult, short hierFontMenuID, long *instanceIndex)
  286. {
  287.     short    theItem = LoWord (menuResult);
  288.     short    theMenuID = HiWord (menuResult);
  289.     gxFont    fontID = nil;
  290.     Str255    str;
  291.  
  292.     *instanceIndex = 0;
  293.  
  294.     if (theMenuID == hierFontMenuID)
  295.     {    GetMenuItemText(GetMenuHandle(theMenuID), theItem, str);
  296.         GXFindFonts(nil, gxFamilyFontName, gxMacintoshPlatform, gxRomanScript, gxEnglishLanguage, str[0], str+1, 1,1, &fontID);
  297.         if (GXFindFonts(fontID, gxFamilyFontName, gxNoPlatform, gxNoScript, gxNoLanguage, 0, nil, 1, gxSelectToEnd, nil) > 1)
  298.             GXFindFonts(fontID, gxStyleFontName, gxMacintoshPlatform, gxRomanScript, gxEnglishLanguage, 7, (unsigned char*)"Regular", 1,1, &fontID);
  299.     }
  300.     else if ((theMenuID > 0) && (theMenuID < 235))        /* range of hierarchial submenus && assume owner is hierfontMenuID */
  301.     {    MenuHandle  mh;
  302.         long    index;
  303.  
  304.         mh = GetMenuHandle(theMenuID);
  305.         BlockMove ( (**mh).menuData, str, (**mh).menuData[0]+1 );   /*the title of gxStyle menu is the family name*/
  306.         GXFindFonts(nil, gxFamilyFontName, gxMacintoshPlatform, gxRomanScript, gxEnglishLanguage, str[0], str+1, 1,1, &fontID);
  307.  
  308.         index = theItem - (CountMItems( mh ) - GXCountFontInstances(fontID)) ;
  309.         if (index > 0)    /*it's an instance*/
  310.             *instanceIndex = index;
  311.         else
  312.         {    GetMenuItemText(mh, theItem, str);
  313.             GXFindFonts(fontID, gxStyleFontName, gxMacintoshPlatform, gxRomanScript, gxEnglishLanguage, str[0], str+1, 1,1, &fontID);
  314.         }
  315.     }   
  316.     HiliteMenu (0);
  317.     return fontID;
  318. }
  319.  
  320. boolean DoHierFontMenuCommandStyle(long menuResult, short hierFontMenuID, gxStyle aStyle, long matchInfo)
  321. {
  322.     short    theItem = LoWord (menuResult);
  323.     short    theMenuID = HiWord (menuResult);
  324.     gxFont    sfnt;
  325.     boolean    success = true;
  326.     long        instanceIndex;
  327.  
  328.     if (sfnt = DoHierFontMenuCommand(menuResult,  hierFontMenuID,  &instanceIndex))
  329.     {    if (matchInfo && ((theMenuID == hierFontMenuID) || (theItem == 0)))        /*theItem was on the family name*/
  330.             SetMatchingStyle(sfnt, aStyle, matchInfo);
  331.         else                    /*no gxStyle matching*/
  332.         {    GXSetStyleFont(aStyle, sfnt);
  333.             if (instanceIndex)
  334.             {    long                howManyVariations;
  335.                 gxFontVariation*    variations;
  336.                 
  337.                 howManyVariations = GXCountFontVariations(sfnt); 
  338.                 variations = (gxFontVariation*)NewPtr(sizeof(gxFontVariation) * howManyVariations);
  339.                 if (variations == nil)
  340.                     goto FAILURE;
  341.                 GXGetFontInstance(sfnt, instanceIndex, variations);
  342.                 GXSetStyleFont(aStyle, sfnt);
  343.                 GXSetStyleFontVariations(aStyle, howManyVariations, variations);
  344.                 DisposePtr((Ptr)variations);
  345.             }
  346.             else
  347.                 GXSetStyleFontVariations(aStyle, 0, nil);
  348.         }
  349.     }
  350.     else    /*not our menu*/
  351. FAILURE:
  352.         success = false;
  353.  
  354.     HiliteMenu (0);
  355.     return(success);
  356. }
  357.  
  358. short DoHierFontMenuCommandShape(long menuResult, short hierFontMenuID,gxShape aShape)
  359. {
  360.     short   theItem = LoWord (menuResult);
  361.     short   theMenuID = HiWord (menuResult);
  362.     gxFont        sfnt;
  363.     short   success = true;
  364.     long        instanceIndex;
  365.  
  366.     sfnt = DoHierFontMenuCommand(menuResult,  hierFontMenuID,  &instanceIndex);
  367.     if (sfnt)
  368.     {
  369.         GXSetShapeFont(aShape, sfnt);
  370.         if(instanceIndex)
  371.         {
  372.             long            howManyVariations;
  373.             gxFontVariation   *variations;
  374.         
  375.             howManyVariations = GXCountFontVariations(sfnt); 
  376.             variations = (gxFontVariation*)NewPtr(sizeof(gxFontVariation) * howManyVariations);
  377.             GXGetFontInstance(sfnt, instanceIndex, variations);
  378.             GXSetShapeFont(aShape, sfnt);
  379.             GXSetShapeFontVariations(aShape, howManyVariations, variations);
  380.             DisposePtr((Ptr)variations);
  381.         }
  382.         else
  383.             GXSetShapeFontVariations(aShape, 0, nil);
  384.     }
  385.     else    /*not our menu*/
  386.         success = false;
  387.     
  388.     HiliteMenu (0);
  389.     return(success);
  390. }
  391.  
  392. long FontToQD(gxFont fontID, long* styleBits)
  393. {
  394.     short resID, i, count;
  395.     OSType resType;
  396.     Str255 resName;
  397.     Handle sfnt;
  398.  
  399.     if (GXGetFont(fontID, (gxFontStorageReference*)&sfnt, nil) != gxResourceFontStorage)
  400.         goto NOT_FOUND;
  401.     GetResInfo(sfnt, &resID, &resType, resName);
  402.     if (ResError())
  403.         goto NOT_FOUND;
  404.  
  405.     count = CountResources('FOND');
  406.     for (i = 1; i <= count; i++)
  407.     {   Handle fond = GetIndResource('FOND', i);
  408.  
  409.         if (!ResError() && fond && *fond)
  410.             do
  411.             {   short* sp = (short*)(*fond + sizeof(FamRec));
  412.                 int entries = *sp++;
  413.                 
  414.                 for (; entries >= 0; --entries)
  415.                 {   if (*sp == 0 && sp[2] == resID)
  416.                     {   if (styleBits)
  417.                             *styleBits = sp[1];
  418.                         GetResInfo(fond, &resID, &resType, resName);
  419.                         return resID;
  420.                     }
  421.                     sp += 3;        /* three elements in the FAT */
  422.                 }
  423.             } while ((fond = XGetNextFOND(fond)) != 0);
  424.     }
  425. NOT_FOUND:
  426.     return 0;
  427. }
  428.  
  429. /*************** font features *************/
  430.  
  431. long GetMenuRunFeatures(MenuHandle menu, gxFont fontID, gxRunFeature feature[])
  432. {
  433.     long i, featureCount, item, count;
  434.  
  435.     count = 0;
  436.     item = 1;
  437.     featureCount = GXCountFontFeatures(fontID);
  438.     for (i = 1; i <= featureCount; i++)
  439.     {    long settingCount, j;
  440.         gxFontFeature featureType;
  441.         gxFontFeatureSetting* settings;
  442.  
  443.         GXGetFontFeature(fontID, i, nil, &settingCount, nil, &featureType);
  444.         settings = (gxFontFeatureSetting*)NewPtr(settingCount * sizeof(gxFontFeatureSetting));
  445.         GXGetFontFeature(fontID, i, nil, nil, settings, nil);
  446.         for (j = 0; j < settingCount; j++)
  447.         {    short mark;
  448.                     
  449.                     GetItemMark(menu, item, &mark);
  450.                     if (mark)
  451.                     {    if (feature)
  452.                         {    feature[count].featureType = featureType;
  453.                             feature[count].featureSelector = settings[j].setting;
  454.                         }
  455.                         ++count;
  456.                     }
  457.                     ++item;
  458.         }
  459.         DisposePtr((Ptr)settings);
  460.         if (i < featureCount)
  461.             ++item;        /* skip the underline */
  462.     }
  463.     return count;
  464. }
  465.  
  466. static boolean SearchRunFeatures(long count, const gxRunFeature feature[], gxFontFeature featureType, long featureSetting)
  467. {    
  468.     if (count)
  469.     {    const gxRunFeature *stop = feature + count;
  470.         do {
  471.             if (feature->featureType == featureType && feature->featureSelector == featureSetting)
  472.                 return true;
  473.             ++feature;
  474.         } while (feature < stop);
  475.     }
  476.     return false;
  477. }
  478.  
  479. void SetMenuRunFeatures(MenuHandle menu, gxFont fontID, long count, const gxRunFeature feature[])
  480. {
  481.     long i, featureCount, item;
  482.  
  483.     item = 1;
  484.     featureCount = GXCountFontFeatures(fontID);
  485.     for (i = 1; i <= featureCount; i++)
  486.     {    long settingCount, j;
  487.         gxFontFeature featureType;
  488.         gxFontFeatureSetting* settings;
  489.  
  490.         GXGetFontFeature(fontID, i, nil, &settingCount, nil, &featureType);
  491.         settings = (gxFontFeatureSetting*)NewPtr(settingCount * sizeof(gxFontFeatureSetting));
  492.         GXGetFontFeature(fontID, i, nil, nil, settings, nil);
  493.         for (j = 0; j < settingCount; j++)
  494.         {    CheckItem(menu, item, SearchRunFeatures(count, feature, featureType, settings[j].setting));
  495.                     ++item;
  496.         }
  497.         DisposePtr((Ptr)settings);
  498.         if (i < featureCount)
  499.             ++item;        /* skip the underline */
  500.     }
  501. }
  502.  
  503. static gxRunFeature* CopyDefaultFeatures(gxFont fontID, long* featureCount)
  504. {
  505.     long count;
  506.     gxRunFeature* feature = nil;
  507.  
  508.     if (count = GetDefaultFontFeatures(fontID, nil))
  509.         if (feature = (gxRunFeature*)NewPtr(count * sizeof(gxRunFeature)))
  510.             GetDefaultFontFeatures(fontID, feature);
  511.         else
  512.             count = 0;
  513.     if (featureCount)
  514.         *featureCount = count;
  515.     return feature;
  516. }
  517.  
  518. void FontFeatureMenu(MenuHandle menu, gxFont fontID)
  519. {
  520.     long i, featureCount;
  521.     Str255 name;
  522.  
  523.     DeleteMenuItems(menu);
  524.     featureCount = GXCountFontFeatures(fontID);
  525.     for (i = 1; i <= featureCount; i++)
  526.     {    long settingCount, j;
  527.         gxFontFeatureSetting* settings;
  528.  
  529.         GXGetFontFeature(fontID, i, nil, &settingCount, nil, nil);
  530.         settings = (gxFontFeatureSetting*)NewPtr(settingCount * sizeof(gxFontFeatureSetting));
  531.         GXGetFontFeature(fontID, i, nil, nil, settings, nil);
  532.         for (j = 0; j < settingCount; j++)
  533.         {    FindFontPName(fontID, settings[j].nameID, name);
  534.                     AppendMenu(menu, name);
  535.         }
  536.         DisposePtr((Ptr)settings);
  537.         if (i < featureCount)
  538.             AppendMenu(menu, "\p(-");
  539.     }
  540. }
  541.  
  542. void ToggleFeatureMenuItem(MenuHandle menuH, gxFont fontID, int item)
  543. {
  544.     long i, currItem, featureCount;
  545.  
  546.     featureCount = GXCountFontFeatures(fontID);
  547.     currItem = 1;
  548.     for (i = 1; i <= featureCount; i++)
  549.     {    long settingCount;
  550.         gxFontFeatureFlag flag;
  551.  
  552.         GXGetFontFeature(fontID, i, &flag, &settingCount, nil, nil);
  553.         if (item < currItem + settingCount)
  554.         {    short mark;
  555.         
  556.             GetItemMark(menuH, item, &mark);
  557.             if (flag & gxMutuallyExclusiveFeature)
  558.             {    if (mark == noMark)
  559.                     for (i = currItem; i < currItem + settingCount; i++)
  560.                         CheckItem(menuH, i, i == item);
  561.             }
  562.             else
  563.                 CheckItem(menuH, item, mark == noMark);
  564.             break;
  565.         }
  566.         currItem += settingCount + 1;        /* +1 to skip the dashed divider */
  567.     }
  568. }
  569.  
  570. void ToggleFeatureMenuFeature(MenuHandle menuH, gxFont fontID, gxRunFeature feature)
  571. {
  572.     int    currItem = 1;
  573.     long    i, j, featureCount = GXCountFontFeatures(fontID);
  574.  
  575.     for (i = 1; i <= featureCount; i++)
  576.     {    long                settingCount;
  577.         gxFontFeatureFlag    flag;
  578.         gxFontFeature        featureType;
  579.  
  580.         GXGetFontFeature(fontID, i, &flag, &settingCount, nil, &featureType);
  581.         if (feature.featureType == featureType)
  582.         {    gxFontFeatureSetting* settings;
  583.         
  584.             if (settings = (gxFontFeatureSetting*)NewPtr(settingCount * sizeof(gxFontFeatureSetting)))
  585.             {    GXGetFontFeature(fontID, i, nil, nil, settings, nil);
  586.                 for (j = 0; j < settingCount; j++)
  587.                     if (settings[j].setting == feature.featureSelector)
  588.                     {    short mark, item = currItem + j;
  589.                     
  590.                         GetItemMark(menuH, item, &mark);
  591.                         if (flag & gxMutuallyExclusiveFeature)
  592.                         {    if (mark == noMark)
  593.                                 for (j = currItem; j < currItem + settingCount; j++)
  594.                                     CheckItem(menuH, j, j == item);
  595.                         }
  596.                         else
  597.                             CheckItem(menuH, item, mark == noMark);
  598.                         break;
  599.                     }
  600.                 DisposPtr((Ptr)settings);
  601.             }
  602.             break;
  603.         }
  604.         currItem += settingCount + 1;        /* +1 to skip the dashed divider */
  605.     }
  606. }
  607.  
  608. void StyleFeatureMenu(MenuHandle menuH, const gxStyle style)
  609. {
  610.     gxFont fontID = GXGetStyleFont(style);
  611.     long featureCount = GXGetStyleRunFeatures(style, nil);
  612.  
  613.     FontFeatureMenu(menuH, fontID);
  614.     if (featureCount)
  615.     {    gxRunFeature* feature = (gxRunFeature*)NewPtr(featureCount * sizeof(gxRunFeature));
  616.  
  617.         if (feature)
  618.         {    GXGetStyleRunFeatures(style, feature);
  619.             SetMenuRunFeatures(menuH, fontID, featureCount, feature);
  620.             DisposPtr((Ptr)feature);
  621.         }
  622.     }
  623. }
  624.  
  625. typedef struct {
  626.     unsigned long    defaultFlags;            /* The default sub-feature flags for this chain. */
  627.     unsigned long    chainLength;            /* The length of the chain in bytes, including this header. */
  628.     unsigned short    nFeatureEntries;        /* The number of entries in the chain's feature table. */
  629.     unsigned short    nSubtables;            /* The number of subtables in the chain. */
  630. } ChainHeader;
  631.  
  632. typedef struct {
  633.     Fixed        version;                /* Version number of the glyph metamorphosis table (0x00010000 for the initial version. */
  634.     unsigned long    nChains;                /* Number of metamorphosis chains which follow. */
  635. } MortHeader;
  636.  
  637. typedef struct {
  638.     unsigned short    featureType;
  639.     unsigned short    featureSetting;
  640.     unsigned long    enableFlags;            /* Flags for sub-features this feature and setting enables. */
  641.     unsigned long    disableFlags;            /* Complement of flags for sub-features this feature and setting disables. */
  642. } FeatureTableEntry;
  643.  
  644. /*
  645.  *    GetFontDefaultFeatures returns a list of features and settings that are on by default in the specified font.
  646.  *    This routine will be added to the next GX Font Manager, as the format for the 'mort' table may change in the future.
  647. */
  648. long GetDefaultFontFeatures(gxFont fontID, gxRunFeature features[])
  649. {
  650.     long mortIndex, defaultFeatureCount = 0;
  651.     
  652.     if (GXFindFontTable(fontID, 'mort', nil, &mortIndex))
  653.     {    MortHeader*    mortHead;
  654.         ChainHeader*    chainHead;
  655.         long            size, chainCount;
  656.         
  657.         size = GXGetFontTable(fontID, mortIndex, nil, nil);
  658.         mortHead = (MortHeader*)NewPtr(size);
  659.         if (mortHead == nil)
  660.             return 0;
  661.         GXGetFontTable(fontID, mortIndex, mortHead, nil);
  662.         chainCount = mortHead->nChains;
  663.  
  664.         chainHead = (ChainHeader*)(mortHead + 1);        
  665.         while (chainCount--)
  666.         {    if (chainHead->nFeatureEntries)
  667.             {    unsigned long        defaultFlags;
  668.                 FeatureTableEntry*    featureEntry;
  669.                 int                featureCount;
  670.                 
  671.                 defaultFlags = chainHead->defaultFlags;
  672.                 featureEntry = (FeatureTableEntry*)(chainHead + 1);
  673.                 featureCount = chainHead->nFeatureEntries;
  674.                 
  675.                 while (featureCount--)
  676.                 {    if (featureEntry->enableFlags && (featureEntry->enableFlags & defaultFlags) == featureEntry->enableFlags)
  677.                     {    if (features)
  678.                         {    features->featureType = featureEntry->featureType;
  679.                             features->featureSelector = featureEntry->featureSetting;
  680.                             ++features;
  681.                         }
  682.                         ++defaultFeatureCount;
  683.                     }
  684.                     ++featureEntry;
  685.                 }
  686.             }
  687.             chainHead = (ChainHeader*)((char*)chainHead + chainHead->chainLength);
  688.         }
  689.         DisposPtr((Ptr)mortHead);
  690.     }
  691.     return defaultFeatureCount;    
  692. }
  693.  
  694. void SetShapeDefaultFeatures(gxShape dst, gxFont fontID)
  695. {
  696.     long featureCount;
  697.     gxRunFeature* feature;
  698.  
  699.     feature = CopyDefaultFeatures(fontID, &featureCount);
  700.     GXSetShapeRunFeatures(dst, featureCount, feature);
  701.     if (feature)
  702.         DisposPtr((Ptr)feature);
  703. }
  704.  
  705. void SetStyleDefaultFeatures(gxStyle dst, gxFont fontID)
  706. {
  707.     long featureCount;
  708.     gxRunFeature* feature;
  709.  
  710.     feature = CopyDefaultFeatures(fontID, &featureCount);
  711.     GXSetStyleRunFeatures(dst, featureCount, feature);
  712.     if (feature)
  713.         DisposPtr((Ptr)feature);
  714. }
  715.  
  716.